package com.atguigu.boot;

import ch.qos.logback.core.db.DBHelper;
import com.atguigu.boot.bean.Pet;
import com.atguigu.boot.bean.User;
import com.atguigu.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @author:朱思博
 * @date:2021/5/4-{13:38}   SpringBoot主程序 固定写法
 */
@SpringBootApplication  // 该注解告诉SpringBoot这是一个SpringBoot应用,称标注了该注解的类为主程序类
public class MainApplication {

    /*
        注意：
            main方法中的这些代码都是学习过程中自己加的，方便理解SpringBoot的各种注解
            实际开发中，主程序只需要
                SpringApplication.run(MainApplication.class, args);
            这样一行代码就可以运行一个简单的HelloWorld程序了
     */

    public static void main(String[] args) {
        // 1.该方法返回一个IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);    // 太强啦！

        // 2.查看容器里面的组件
            // 获取所有组件的名称
        String[] beanDefinitionNames = run.getBeanDefinitionNames();
            // 遍历组件名称数组 有我们熟悉的DispatcherServlet，解决乱码的characterEncodingFilter，视图解析器viewResolver等等
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }

//        // 3.从容器中获取组件 注册的组件默认单例模式
//        Pet tom01 = run.getBean("tom22",Pet.class);
//        Pet tom02 = run.getBean("tom22", Pet.class);
//        System.out.println("组件："+(tom01 == tom02)); // true 证明默认单例模式
//
//        // 4.proxyBeanMethods默认 = true
//            // 由于配置类本身也是一个组件，尝试获取，proxyBeanMethods默认 = true情况下获取到的是一个代理对象
//        MyConfig config1 = run.getBean(MyConfig.class);
//        System.out.println(config1);   // com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$f48b3bc0@56afdf9a
//
//            // 调用配置类中的我们手动声明的@Bean配置组件方法，proxyBeanMethods默认 = true的情况下
//            // 由于该属性为true，获取到的配置类组件是一个代理对象
//            // SpringBoot总会检查这个组件是否在IOC容器中，保持组件单实例
//        User user1 = config1.user01();
//        User user2 = config1.user01();
//        System.out.println(user1 == user2); // true,直接去IOC容器中拿，外部无论调用多少遍该方法拿到的都是之前注册到容器中的单实例
//
//        // 6.proxyBeanMethods = false
//            // 不是默认单例模式的情况下，获取到的配置类组件就不是一个代理对象
//        MyConfig config2 = run.getBean(MyConfig.class);
//        System.out.println(config2);    // com.atguigu.boot.config.MyConfig@6b52dd31
//
//            // 获取到的配置类组件不是一个单例模式，获取Bean每次都会获取到新的对象
//        User user3 = config2.user01();
//        User user4 = config2.user01();
//        System.out.println(user3 == user4); // false
//
//
//        // 7.组件依赖问题，必须是proxyBeanMethods = true才可以
//            // 如果是false，user中的pet是新new的，不是容器中的pet，在SpringBoot新版本中，甚至直接报错
//        User user01 = run.getBean("user01", User.class);
//        Pet tom22 = run.getBean("tom22", Pet.class);
//            // 配置类中user.setPet(tomcatPet());
//            // 看一下user01的宠物是不是我们IOC容器中的宠物
//        System.out.println(user01.getPet() == tom22);   // true 是同一个
//
//        // 8.@Import({User.class, DBHelper.class})查看这些组件是不是真的加入到容器中了
//        System.out.println("===================8===================");
//            // 查看容器中所有User类型的组件
//        String[] beanNamesForType = run.getBeanNamesForType(User.class);
//        for (String s : beanNamesForType) {
//            System.out.println(s);
//            // com.atguigu.boot.bean.User   这个是@Import注解导入的组件，由此可见，@Import注解导入的组件默认名称为类的全类名
//            // user01   // 这个是配置类中@Bean注解导入的组件
//        }
//            // 查看容器中所有DBHelper类型的组件
//        String[] beanNamesForType1 = run.getBeanNamesForType(DBHelper.class);
//        for (String s : beanNamesForType1) {
//            System.out.println(s);
//            // ch.qos.logback.core.db.DBHelper
//        }

        // 9.@ConditionalOnBean注解
            // 该注解属于条件装配，条件装配还有很多注解，条件装配在SpringBoot底层非常重要
            // 取消掉@Bean("tom22")注解，即取消这个组件
        boolean tom22 = run.containsBean("tom22");
        System.out.println(tom22);  // false 代表取消组件成功
            // user组件没加条件的时候
        System.out.println(run.containsBean("user01")); // true
            // user组件加条件ConditionalOnBean(name = "tom22")的时候
        System.out.println(run.containsBean("user01")); // false,表示没有name = tom22这个组件，那加了该注解的组件也不会被注册
            // 该注解要是标注在类上，表示不满足该指定条件的时候，这个类中的所有组件都不会生效

        // 10.@ImportResource 原生配置文件引入注解
            // 以下的两个Bean都是在beans.xml配置文件中
        boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
            // 没引入配置文件的时候自然得不到配置文件中的Bean
        System.out.println(haha);   // false
        System.out.println(hehe);   // false
            // 在任意配置类上@ImportResource("classpath:beans.xml")
        System.out.println(haha);   // true
        System.out.println(hehe);   // true 证明xml配置文件已经成功导入
    }
}
